home *** CD-ROM | disk | FTP | other *** search
- version equ 3
-
- include defs.asm ;SEE ENCLOSED COPYRIGHT MESSAGE
-
- ;Ported from Tim Krauskopf's micnet.asm, an assembly language
- ;driver for the MICOM-Interlan NI5210 by Russell Nelson. Any bugs
- ;are due to Russell Nelson.
-
- ;/*
- ;* NCSA Telnet source code
- ;* National Center for Supercomputing Applications
- ;* November 1, 1987
- ;* (C) Copyright 1987 The Board of Trustees of the University of Illinois
- ;*
- ;* Permission is granted to any individual or institution to use, copy,
- ;* modify, or redistribute this software and its documentation provided
- ;* this notice and the copyright notices are retained. This software
- ;* may not be distributed for profit, either in original form or in
- ;* derivative works. The University of Illinois makes no representations
- ;* about the suitability of this software for any purpose.
- ;* THE UNIVERSITY OF ILLINOIS GIVES NO WARRANTY,
- ;* EITHER EXPRESS OR IMPLIED, FOR THE PROGRAM AND/OR DOCUMENTATION PROVIDED,
- ;* INCLUDING, WITHOUT LIMITATION, WARRANTY OF MERCHANTABILITY AND WARRANTY
- ;* OF FITNESS FOR A PARTICULAR PURPOSE.
- ;*/
-
- code segment byte public
- assume cs:code, ds:code
-
- ;
- ; Equates for controlling the MICOM board
- ;
- ; I/O addresses, writing anything in AL trips these gates
- ;
- ; First six addresses are the EPROM board Ether address (read)
- ;
- IORESET EQU 0 ; reset the board
- IOCA EQU 1 ; execute command which is in SCB
- IODIS EQU 2 ; disable network connect
- IOENA EQU 3 ; enable network
- IOINTON EQU 4 ; enable interrupts
- IOINTOF EQU 5 ; disable interrupts, '586 thinks it still ints
- ;
- ; Structure elements specific to the Intel 82586 chip
- ;
- BDBASE EQU 1874 ; base address for 30 buffer descriptors
- BUFBASE EQU 2174 ; base address for 30 200 byte buffers
- BDSTAT EQU 0 ; status word in BD
- BDLINK EQU 2 ; 16pointer to next BD
- BDPTR EQU 4 ; 24pointer to actual buffer
- BDSIZE EQU 8 ; size of the buffer
- ;
- SCB EQU 10 ; system control block base
- SSTAT EQU 0 ; status word for SCB
- SCOM EQU 2 ; command word in SCB
- SCBL EQU 4 ; 16pointer to command block list
- SRFA EQU 6 ; 16pointer to receive frame list
- SERRS EQU 8 ; 4 words of error counts
- ;
- FDBASE EQU 1214 ; base addr for 30 frame descriptors
- FDSTAT EQU 0 ; status word for frame
- FDEOL EQU 2 ; end of FD list flag
- FDLINK EQU 4 ; 16pointer to next FD
- FDPTR EQU 6 ; 16pointer to list of BD's
- ;
- TSTAT EQU 0 ; status word for xmit
- TCOM EQU 2 ; command to transmit
- TLINK EQU 4 ; 16pointer to next command (always ffff)
- TPTR EQU 6 ; 16pointer to xmit TBD
- TTRIES EQU 8 ; number of transmit retries
- ;
- SCPTR EQU 01ff6h ; hardwired address for SCP
- ISCPTR EQU 01feeh ; my address for ISCP, points to SCB
- CCBPTR EQU 26 ; offset of configure command block
- TCBPTR EQU 44 ; xmit CB offset
- TBDPTR EQU 60 ; xmit BD offset
- TBUFPTR EQU 68 ; xmit buffer offset
-
-
- ;
- ; Data segment
- ;
-
- public int_no
- int_no db 2,0,0,0 ; interrupt number.
- io_addr dw 0360h,0 ; I/O address for card (jumpers)
- base_addr dw 0d000h,0 ; base segment for board (jumper set)
-
- public driver_class, driver_type, driver_name
- driver_class db 1 ;from the packet spec
- driver_type db 11 ;from the packet spec
- driver_name db "NI5210",0 ;name of the driver.
-
- firstfd dw FDBASE ; start of FD queue
- lastfd dw 0 ; end of the FD chain
- lastbd dw 0 ; end of the BD chain
-
-
- public send_pkt
- send_pkt:
- ;enter with ds:si -> packet, cx = packet length.
- ;exit with nc if ok, or else cy if error, dh set to error number.
- assume ds:nothing
- mov ax,base_addr
- mov es,ax ; base for board
-
- mov dx,cx ; save a copy, might be less than 60, ok
-
- cmp dx,RUNT ; minimum length for Ether
- jnb oklen
- mov dx,RUNT ; make sure size at least RUNT
- oklen:
- mov di,TBUFPTR ; start of xmit buffer
-
- ;
- ; check for previous xmit
- ;
- xwait:
- mov bx,word ptr es:[SCB+SCOM] ; is command zeroed yet?
- or bx,bx
- jnz xwait ; not there yet, wait for it
- ;
- ; move the data using word moves.
- ;
- shr cx,1
- jnc send_even
- movsb
- send_even:
- rep movsw ; copy into buffer
- ;
- ; put the correct size into the TDB
- ;
- or dx,08000h ; end of frame bit flag
- mov word ptr es:[TBDPTR],dx ; store it
- mov word ptr es:[TCBPTR],0 ; zero status wd
- mov word ptr es:[TCBPTR+TCOM],08004h; xmit command in TCB
- mov word ptr es:[SCB+SCOM],0100h ; execute command
-
- loadport
- setport IOCA
- out dx,al ; issue CA to get it going
-
- ret
-
-
- public get_address
- get_address:
- ;get the address of the interface.
- ;enter with es:di -> place to get the address, cx = size of address buffer.
- ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
- assume ds:code
- cmp cx,EADDR_LEN ;make sure that we have enough room.
- jb get_address_2
- mov cx,EADDR_LEN
- mov dx,io_addr ; Get our IO base address.
- cld
- get_address_1:
- in al,dx ; get a byte of the eprom address
- stosb ; put it away
- inc dx ; next register
- loop get_address_1 ; go back for rest
- mov cx,EADDR_LEN
- clc
- ret
- get_address_2:
- stc
- ret
-
-
- public reset_interface
- reset_interface:
- ;reset the interface.
- ;we don't do anything.
- ret
-
-
- ;called when we want to determine what to do with a received packet.
- ;enter with cx = packet length, es:di -> packet type.
- extrn recv_find: near
-
- ;called after we have copied the packet into the buffer.
- ;enter with ds:si ->the packet, cx = length of the packet.
- extrn recv_copy: near
-
- extrn count_in_err: near
- extrn count_out_err: near
-
- public recv
- recv:
- ;called from the recv isr. All registers have been saved, and ds=cs.
- ;Upon exit, the interrupt will be acknowledged.
- mov ds,base_addr ; base for board
- assume ds:nothing
-
- mov ax,ds:[SCB+SSTAT] ;get the status.
- recv_isr_1:
- cmp word ptr ds:[SCB+SCOM],0 ;are we done yet?
- jne recv_isr_1 ;no -- keep waiting.
-
- and ax,0f000h ;isolate the ACK bits.
- mov ds:[SCB+SCOM],ax ;make a command to
- ;acknowledge the interrupt.
- loadport
- setport IOCA
- out dx,al
-
- ; Get whatever packets are on the board
- ;
- mov bx,firstfd ; get addr of first FD in list
- ;
- ;
- ckframe:
- mov ax,[bx+FDSTAT] ; status word of frame
- test ax,08000h ; frame written?
- jnz okframe
-
- jmp ru_start ; no, restore receiver if necessary
- ptrupdate_j_1:
- jmp ptrupdate
- frame_bad_j_1:
- call count_in_err
- jmp frame_bad
-
- ; we have a frame, read it in
- ;
- okframe:
-
- test ax,02000h ;check frame OK bit
- jz frame_bad_j_1 ;bad, fix it.
- mov si,[bx+FDPTR] ;get pointer to buffer descriptor
- xor cx,cx ;start with zero bytes.
- countbuf: ;es:di is already set to receive packet
- mov dx,si ;save a copy of current BD ptr
- mov ax,[si+BDSTAT] ;get status and count word for BD
- test ax,04000h ;is count field there?
- jz ptrupdate_j_1 ;no - we give up here.
- add cl,al ;add the count into cx.
- adc ch,0
- mov si,[si+BDLINK] ;go to next BD in list
- test ax,8000h ;is this the last frame?
- je countbuf ;no - keep counting.
-
- mov ax,0 ;we have the size needed.
- push bx
- push cx
-
- mov ax,cs ;we need ds = code.
- mov ds,ax
- assume ds:code
-
- mov es,base_addr ;get a pointer to their type.
- mov di,es:[bx+FDPTR] ;get pointer to buffer descriptor
- mov di,es:[di+BDPTR] ;get offset of data
- add di,EADDR_LEN+EADDR_LEN ;skip the ethernet addreses and
- ; point to the packet type.
-
- call recv_find ;look up our type.
-
- pop cx
- pop bx
- mov ds,base_addr ;restore ds to the board.
- assume ds:nothing
-
- mov ax,es ;is this pointer null?
- or ax,di
- je ptrupdate ;yes - just free the frame.
-
- push cx
- push es ;remember where the buffer pointer is.
- push di
-
- mov si,[bx+FDPTR] ;get pointer to buffer descriptor
- copybuf:
- mov dx,si ;save a copy of current BD ptr
- xor ch,ch ;200 bytes is largest this can be
- mov cl,[si+BDSTAT] ;get count word for BD
- mov si,[si+BDPTR] ;get offset of data
- shr cx,1 ;move the data using a word move.
- jnc recv_even
- movsb
- recv_even:
- rep movsw ;copy the bytes from this packet segment
- mov si,dx ;get back current BD ptr
- test [si+BDSTAT],8000h ;check EOF bit
- mov si,[si+BDLINK] ;go to next BD in list
- jz copybuf ;not done, keep copying it.
-
- pop si ;now give the frame to the client.
- pop ds
- pop cx
- assume ds:nothing
-
- call recv_copy
-
- jmp short ptrupdate
-
- frame_bad:
- ;
- ; we are done with the frame, do the list management
- ;
- ptrupdate:
- push cs
- pop ds
- assume ds:code
- mov es,base_addr ; reload board segment
-
- mov si,es:[bx+FDPTR] ; first BD in frame list
- nextbd:
- mov cx,es:[si+BDSTAT] ; count word for BD, EOF bit
- test cx,08000h ; EOF bit, if set, save si in lastbd
- jnz dolastbd
- mov word ptr es:[si+BDSTAT],0 ; clear status word, EOF bit
- cmp si,lastbd ; see if we are wrapping
- jz dolastbd ; yes, just undo it
- mov si,es:[si+BDLINK] ; follow link
- jmp nextbd
- dolastbd:
- mov di,lastbd ; where end of BD list is now
- mov lastbd,si ; store last known BD
- mov word ptr es:[si+BDSIZE],08000h+200 ; end of list here
- mov word ptr es:[si+BDSTAT],0 ; clear status word, EOF bit
- ; size field for not end of list
- mov word ptr es:[di+BDSIZE],200 ; remove old end-of-list
-
- ;
- ; update the FD list flags, new end-of-list
- ;
- mov word ptr es:[bx+FDEOL],08000h ; store new EOL
- mov word ptr es:[bx+FDSTAT],0 ; clear status word for frame
- mov di,lastfd ; get old end-of-list
- mov word ptr es:[di+FDEOL],0 ; zero old one
- mov lastfd,bx ; update stored pointer
- mov si,es:[bx+FDLINK] ; where next fd is
- mov firstfd,si ; store that info for next time
-
- ru_start:
- ; re-start receive unit
- ;
- ; check to see if the receiver went off because of no resources
- ; and restart receiver if necessary
- ;
- call count_out_err
-
- push cs
- pop ds
- mov es,base_addr
- mov ax,es:[SCB+SSTAT] ; status word for SCB
- and ax,070h ; receiver status
- cmp al,020h ; receiver has no resources
- jnz hasres
- ;
- ; setup lists for starting the RU on the chip
- ; we know that there isn't anything in the buffer that we want
- ;
-
- mov bx,firstfd ; get first FD on free list (assume free)
- mov word ptr es:[SCB+SRFA],bx ; put into SCB
- mov si,lastbd ; pointer to a BD, end of chain
- mov ax,word ptr es:[si+BDLINK] ; pointer to next BD
- mov word ptr es:[bx+FDPTR],ax ; set to start of BDs
- ;
- ;
- ; Start the RU, doesn't need CB, only SCB parms.
- ; command, to start receiving again
- ;
- mov word ptr es:[SCB+SSTAT],0 ; clear status word
- mov word ptr es:[SCB+SCOM],010h ; start RU
- loadport
- setport IOCA
- out dx,al
- hasres:
- ret
-
-
- end_resident label byte
-
- public usage_msg
- usage_msg db "usage: ni5210 <packet_int_no> <int_no> <io_addr> <base_addr>",CR,LF,'$'
-
- public copyright_msg
- copyright_msg db "Packet driver for the MICOM-Interlan NI5210, version ",'0'+version,CR,LF
- db "Portions Copyright 1988 The Board of Trustees of the University of Illinois",CR,LF,'$'
-
- no_5210_msg db "No 5210 found at that address.",CR,LF,'$'
- timeout_msg db "Timed out while initializing 5210.",CR,LF,'$'
- int_no_name db "Interrupt number ",'$'
- io_addr_name db "I/O port ",'$'
- base_addr_name db "Memory address ",'$'
-
- extrn set_recv_isr: near
-
-
- ;enter with si -> argument string, di -> word to store.
- ;if there is no number, don't change the number.
- extrn get_number: near
-
- ;enter with dx:ax = number to print.
- extrn hexout: near, decout: near
-
- public parse_args
- parse_args:
- mov di,offset int_no
- mov bx,offset int_no_name
- call get_number
- mov di,offset io_addr
- mov bx,offset io_addr_name
- call get_number
- mov di,offset base_addr
- mov bx,offset base_addr_name
- call get_number
- ret
-
-
- timeout_error:
- mov dx,offset timeout_msg
- jmp short error
- no_5210_error:
- mov dx,offset no_5210_msg
- error:
- mov ah,9
- int 21h
- stc
- ret
-
- ;
- ; data for configuring and setting up the MICOM board
- ;
- ; chip always looks at SCP for config info which points to ISCP for the
- ; pointer to the CONTROL BLOCK which handles everything from there.
- ; Kind of indirect, but it works.
- ;
- SCP DB 1 ; bus use flag
- DB 5 DUP(0) ; unused
- DW ISCPTR ; 24pointer to ISCP offset
- DW 0 ; high part
- ;
- ; Intermediate SCP
- ;
- ISCP DW 1 ; busy flag
- DW SCB ; 16pointer to SCB
- DW 0,0 ; base for all 16 pointers, lo, hi
- ; board is hardwired to 0 for these values
- ;
- ; Configuration block for 82586, this comprises one config command
- ; Parameters taken from MICOM driver
- ;
- CBCONF DW 0 ; status word
- DW 8002H ; end of command list + configure command
- DW 0ffffh ; link to next command (not used)
- DW 080CH ; fifo=8, byte count=C
- DW 2E00H ; important! Addr (AL) not inserted on the fly!
- DW 6000H ; IFS = 60h
- DW 0F200H ; retry=F, slot time=200h
- DW 0 ; flags, set to 1 for promiscuous
- DW 40H ; min frame length=40h
- ;
- ; CB for xmit, followed by BD for xmit, copied together
- ;
- TCB DW 0 ; status word
- DW 08004H ; command word for xmit + EL
- DW 0ffffh ; no command link
- DW TBDPTR ; 16pointer to xmit BD
- DW 0,0,0,0 ; no addressing used here
- ;
- ; BD template for xmit
- TBD DW 0
- DW 0 ; next BD pointer, unused
- DW TBUFPTR ; 24pointer to xmit buffer
- DW 0 ; high part of pointer
-
-
- public etopen
- etopen:
- ; Initialize the Ethernet board, set receive type.
- ;
- ; check for correct EPROM location
- ;
- mov dx,io_addr ; i/o address
- add dx,EADDR_LEN ; look past the ethernet address.
- in al,dx
- mov bl,al ; assemble pattern to check
- inc dx
- in al,dx
- mov bh,al
- cmp bx,05500h ; pattern known to be there in ROM
- jz have_5210
- jmp no_5210_error ;not there -- no 5210.
- have_5210:
- ;
- ; Initialize MICOM 5210
- ;
- ; Install 8K SCP, we only use 8K bytes no matter what
- ;
- mov es,base_addr ; set to base address
- mov di,SCPTR
- mov si,offset SCP ; get pre-set values
- mov cx,5 ; 5 words
- rep movsw ; install SCP
- ;
- ; Install 16K SCP, just in case they have that much.
- ;
- mov si,offset SCP ; get pre-set values
- mov di,SCPTR+2000h ; offset for 16K board
- mov cx,5 ; 5 words
- rep movsw ; install SCP
- ;
- ; Intermediate SCP
- ;
- mov si,offset ISCP ; addr of pre-set values
- mov di,ISCPTR
- mov cx,4 ; 4 words
- rep movsw ; install ISCP
- ;
- ; Turn off interrupts, I don't want them
- ;
- loadport
- setport IORESET
- out dx,al ; reset the chip
- ;
- ; Issue a CA to initialize the chip after reset
- ;
- setport IOCA
- out dx,al ; CA
- ;
- ; Disconnect from network
- setport IODIS
- out dx,al
- ;
- ; configure 82586
- ;
- mov si,offset CBCONF ; configure command
- mov di,CCBPTR ; where command will reside
- mov cx,9
- rep movsw ; copy to board
- ;
- ; issue the configure command
- ;
- mov word ptr es:[SCB+SCOM],0100h ; do-command command
- mov word ptr es:[SCB+SCBL],CCBPTR ; where conf command is
- mov word ptr es:[SCB+SERRS],0 ; zero errs field
- mov word ptr es:[SCB+SERRS+2],0 ; zero errs field
- mov word ptr es:[SCB+SERRS+4],0 ; zero errs field
- mov word ptr es:[SCB+SERRS+6],0 ; zero errs field
- setport IOCA
- out dx,al ; send it
- xor cx,cx ; timeout
- waitconf:
- mov ax,word ptr es:[CCBPTR] ; get status word
- test ax,08000h ; is command complete?
- loopz waitconf
- jnz confok
- jmp timeout_error
- confok:
- ;
- ; Next step, load our address into the board
- ; reuses the space that the configure command used, with different command
- ;
- mov di,CCBPTR ; start of config command block
- xor ax,ax
- stosw ; zero status word for commmand
- mov ax,8001h ; IA setup command + EL
- stosw
- xor ax,ax
- dec ax
- stosw ; set link value to -1 (unused)
- ;
- ; move my addr onto board location inside IA command
- ;
- mov dx,io_addr ; Get our IO base address
- mov cx,EADDR_LEN
- store_address_1:
- in al,dx ; get a byte of the eprom address
- stosb ; put it away
- inc dx ; next register
- loop store_address_1 ; go back for rest
-
- ;
- ; start the IA setup command
- ;
- mov word ptr es:[SCB+SCOM],0100h ; do-command command
- loadport
- setport IOCA
- out dx,al ; send it
- xor cx,cx ; timeout
- waitia:
- mov ax,word ptr es:[CCBPTR] ; get status word
- test ax,08000h ; is command complete?
- loopz waitia
- jnz iaok
- jmp timeout_error
- iaok:
- ;
- ; IA sent, setup all of the other data structures on the board
- ; start with xmit command descriptors
- ;
- mov si,offset TCB ; template for xmit
- mov di,TCBPTR ; where it goes on board
- mov cx,12 ; copies CB and BD for xmit
- rep movsw
- ;
- ; Set up frame and buffer descriptors, 30 each
- ;
- mov cx,30 ; # of FDs
- mov di,FDBASE ; base addr for FDs
- fdloop:
- xor ax,ax
- mov bx,di ; save pointer
- stosw ; clear status wd
- stosw ; clear EL field
- add bx,22 ; points to next one
- mov es:[di],bx ; put in link ptr
- inc di
- inc di
- dec ax
- stosw ; clear BD ptr to -1
- add di,14
- loop fdloop
-
- sub di,20 ; point back to last EL field
- mov ax,08000h ; end of list
- stosw ; put into last FD
- sub di,4 ; back to beginning of last FD
- mov lastfd,di ; save the pointer
- mov word ptr es:[di+FDLINK],FDBASE ; make list circular,
- ; from last to first
-
- mov ax,BDBASE ; first BD
- mov word ptr es:[FDBASE+FDPTR],ax ; put it in the first FD frame
- ;
- ; now BDs
- mov cx,30
- mov di,BDBASE ; start of BD area
- mov dx,BUFBASE ; start of buffer area
- bdloop:
- xor ax,ax
- mov bx,di ; save pointer
- stosw ; zero status field
- add bx,10 ; point to next record
- mov es:[di],bx ; put in link ptr
- inc di
- inc di
- mov es:[di],dx ; address of buffer, lo part
- inc di
- inc di
- stosw ; zero out high part
- mov ax,200
- stosw ; store length field
- add dx,ax ; add in length of buffer, updates ptr
- loop bdloop
-
- sub di,2 ; back to last BD size field
- mov ax,08000h+200 ; end of list + 200
- stosw ; mark end of list
- sub di,8 ; back to last BDLINK field
- mov ax,BDBASE
- stosw ; put link to beginning of list here
- sub di,4 ; back to beginning of last BD
- mov lastbd,di ; save pointer to end of list
- ;
- ; minor detail, but important
- ; Change SCB command block pointer to setup for xmit commands
- ; = only commands needed when operational
- ;
- mov word ptr es:[SCB+SCBL],TCBPTR ; where xmit command is
- ;
- ; configure to connect to network
- ;
- loadport
- setport IOENA ; enable network
- out dx,al ; any al value
- ;
- ; Start the RU, doesn't need CB, only SCB parms.
- ; command, to start receiving
- ;
- mov word ptr es:[SCB],0 ; clear status word
- mov word ptr es:[SCB+SRFA],FDBASE ; set to frame descriptors
- mov word ptr es:[SCB+SCOM],010h ; start RU
- setport IOCA
- out dx,al
-
- ;
- ; Now reset CX, FR, CNA, and RNR so that we don't get a spurious interrupt.
- ;
- store_ack_1:
- cmp word ptr es:[SCB+SCOM],0 ;are we done yet?
- jne store_ack_1 ;no -- keep waiting.
-
- mov ax,es:[SCB+SSTAT] ;get the status.
- and ax,0f000h ;isolate the ACK bits.
- mov es:[SCB+SCOM],ax ;make a command to
- ;acknowledge the interrupt.
-
- setport IOCA
- out dx,al
-
- ;
- ; Now hook in our interrupt
- ;
- call set_recv_isr
- mov dx,offset end_resident
- clc
- ret
-
-
- code ends
-
- end
-